/*
 * Open Source Physics software is free software as described near the bottom of this code file.
 *
 * For additional information and documentation on Open Source Physics please see:
 * <http://www.opensourcephysics.org/>
 */

package org.opensourcephysics.controls;
import javax.swing.text.*;
import java.awt.*;
import javax.swing.*;
import java.util.logging.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import org.opensourcephysics.tools.ToolsRes;

/**
 * MessageFrame displays text messages.
 *
 * The static MessageFrame object displays logger messages when a program is run as a applet.
 *
 * @author W. Christian
 * @version 1.0
 */
public class MessageFrame extends JFrame {

   static final Color DARK_GREEN = new Color(0, 128, 0), DARK_BLUE = new Color(0, 0, 128),
                      DARK_RED = new Color(128, 0, 0);
   static Style black, red, blue, green, magenta, gray;
   static MessageFrame APPLET_MESSAGEFRAME;
   //static Level levelOSP = Level.CONFIG;
   static int levelOSP = Level.CONFIG.intValue();
   private static int OFF=Level.OFF.intValue(), SEVERE=Level.SEVERE.intValue(), WARNING=Level.WARNING.intValue(),
      INFO=Level.INFO.intValue(),ERR=ConsoleLevel.ERR_CONSOLE.intValue(),OUT=ConsoleLevel.OUT_CONSOLE.intValue(),
      CONFIG=Level.CONFIG.intValue(),FINE=Level.FINE.intValue(),FINER=Level.FINER.intValue(),FINEST=Level.FINEST.intValue(),ALL=Level.ALL.intValue();
   private JTextPane textPane;
   private static ArrayList buttonList = new ArrayList();
   private MessageFrame() {
      // create the panel, text pane and scroller
      setTitle(ControlsRes.getString("MessageFrame.DefaultTitle")); //$NON-NLS-1$
      JPanel logPanel = new JPanel(new BorderLayout());
      logPanel.setPreferredSize(new Dimension(480, 240));
      setContentPane(logPanel);
      textPane = new JTextPane();
      logPanel.setPreferredSize(new Dimension(200, 300));
      logPanel.setMinimumSize(new Dimension(100, 100));
      textPane.setEditable(false);
      textPane.setAutoscrolls(true);
      black = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE);
      red = textPane.addStyle("red", black); //$NON-NLS-1$
      StyleConstants.setForeground(red, DARK_RED);
      blue = textPane.addStyle("blue", black); //$NON-NLS-1$
      StyleConstants.setForeground(blue, DARK_BLUE);
      green = textPane.addStyle("green", black); //$NON-NLS-1$
      StyleConstants.setForeground(green, DARK_GREEN);
      magenta = textPane.addStyle("magenta", black); //$NON-NLS-1$
      StyleConstants.setForeground(magenta, Color.MAGENTA);
      gray = textPane.addStyle("gray", black); //$NON-NLS-1$
      StyleConstants.setForeground(gray, Color.GRAY);
      JScrollPane textScroller = new JScrollPane(textPane);
      textScroller.setWheelScrollingEnabled(true);
      logPanel.add(textScroller, BorderLayout.CENTER);
      pack();
   }

   /**
    * Shows the static APPLET_MESSAGEFRAME that is being used to show logger messages in applet mode.
    * @param b boolean
    */
   public static void showLog(boolean b) {
      if((APPLET_MESSAGEFRAME==null)||!APPLET_MESSAGEFRAME.isDisplayable()) {
         createAppletMessageFrame();
      }
      APPLET_MESSAGEFRAME.setVisible(b);
   }

   private static void createAppletMessageFrame() {
      APPLET_MESSAGEFRAME = new MessageFrame();
      APPLET_MESSAGEFRAME.setSize(300,200);
      APPLET_MESSAGEFRAME.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
      JMenuBar menuBar = new JMenuBar();
      APPLET_MESSAGEFRAME.setJMenuBar(menuBar);
      final JMenu editMenu = new JMenu(ControlsRes.getString("MessageFrame.Edit_menu")); //$NON-NLS-1$
      menuBar.add(editMenu);
      final JMenuItem clearItem = new JMenuItem(ControlsRes.getString("MessageFrame.Clear_menu_item")); //$NON-NLS-1$
      editMenu.add(clearItem);
      clearItem.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            APPLET_MESSAGEFRAME.textPane.setText(""); //$NON-NLS-1$
         }
      });
      final JMenu levelMenu = new JMenu(ControlsRes.getString("MessageFrame.Level_menu")); //$NON-NLS-1$
      menuBar.add(levelMenu);
      ButtonGroup menubarGroup = new ButtonGroup();
      for(int i = 0; i<OSPLog.levels.length; i++) {
         JRadioButtonMenuItem item = new JRadioButtonMenuItem(OSPLog.levels[i].getName());
         buttonList.add(item);
         levelMenu.add(item, 0);
         menubarGroup.add(item);
         if(levelOSP==OSPLog.levels[i].intValue()) {
            item.setSelected(true);
         }
         item.setActionCommand(OSPLog.levels[i].getName());
         item.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
               setLevel(ConsoleLevel.parse(e.getActionCommand()));
            }
         });
      }
      ToolsRes.addPropertyChangeListener("locale", new PropertyChangeListener(){ //$NON-NLS-1$
         public void propertyChange(PropertyChangeEvent e){
            APPLET_MESSAGEFRAME.setTitle(ControlsRes.getString("MessageFrame.DefaultTitle")); //$NON-NLS-1$
            editMenu.setText(ControlsRes.getString("MessageFrame.Edit_menu")); //$NON-NLS-1$
            clearItem.setText(ControlsRes.getString("MessageFrame.Clear_menu"));
            levelMenu.setText(ControlsRes.getString("MessageFrame.Level_menu"));
         }
      });

   }

   /**
    * Gets the visible property.
    *
    * @return boolean
    */
   public static boolean isLogVisible() {
      if(APPLET_MESSAGEFRAME==null) {
         return false;
      } else {
         return APPLET_MESSAGEFRAME.isVisible();
      }
   }

   /**
    * Clears the text.
    */
   public static void clear() {
      if(APPLET_MESSAGEFRAME!=null) {
         APPLET_MESSAGEFRAME.textPane.setText(""); //$NON-NLS-1$
      }
   }

   /**
    * Sets the logger level;
    * @param level Level
    */
   public static void setLevel(Level level) {
      levelOSP = level.intValue();
      for(int i = 0, n=Math.min(OSPLog.levels.length,buttonList.size()); i<n; i++) {
         if (levelOSP==OSPLog.levels[i].intValue()){
            ((JRadioButtonMenuItem)buttonList.get(i)).setSelected(true);
         }
      }
   }

   /**
    * Logs an severe error message.
    * @param msg String
    */
   public static void severe(String msg) {
      if(levelOSP<= SEVERE)appletLog(msg, MessageFrame.red);
   }

   /**
    * Logs a warning message.
    * @param msg String
    */
   public static void warning(String msg) {
      if(levelOSP <= WARNING)appletLog(msg, MessageFrame.red);
   }

   /**
    * Logs an information message.
    * @param msg String
    */
   public static void info(String msg) {
      if(levelOSP<= INFO)appletLog(msg, MessageFrame.black);
   }

   /**
    * Logs a configuration message.
    * @param msg String
    */
   public static void config(String msg) {
      if(levelOSP <= CONFIG)appletLog(msg, MessageFrame.green);
   }

   /**
    * Logs a fine debugging message.
    * @param msg String
    */
   public static void fine(String msg) {
      if(levelOSP <= FINE)appletLog(msg, MessageFrame.blue);
   }

   /**
    * Logs a finer debugging message.
    * @param msg String
    */
   public static void finer(String msg) {
      if(levelOSP<= FINER)appletLog(msg, MessageFrame.blue);
   }

   /**
    * Logs a finest debugging message.
    * @param msg String
    */
   public static void finest(String msg) {
      if(levelOSP <= FINEST)appletLog(msg, MessageFrame.blue);
   }

   private static void appletLog(final String msg, final Style style) {
      if((APPLET_MESSAGEFRAME==null)||!APPLET_MESSAGEFRAME.isDisplayable()) {
         createAppletMessageFrame();
      }
      Runnable refreshText = new Runnable() {

         public synchronized void run() {
            try {
               Document doc = APPLET_MESSAGEFRAME.textPane.getDocument();
               doc.insertString(doc.getLength(), msg+'\n', style);
               // scroll to display new message
               Rectangle rect = APPLET_MESSAGEFRAME.textPane.getBounds();
               rect.y = rect.height;
               APPLET_MESSAGEFRAME.textPane.scrollRectToVisible(rect);
            } catch(BadLocationException ex) {
               System.err.println(ex);
            }
         }
      };
      if(SwingUtilities.isEventDispatchThread()) {
         refreshText.run();
      } else {
         SwingUtilities.invokeLater(refreshText);
      }
   }
   /*
    * public static void main(String[] args) {
    *   MessageFrame.fine("test fine");
    *   APPLET_LOG.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    * }
    */
}
/*
 * Open Source Physics software is free software; you can redistribute
 * it and/or modify it under the terms of the GNU General Public License (GPL) as
 * published by the Free Software Foundation; either version 2 of the License,
 * or(at your option) any later version.
 *
 * Code that uses any portion of the code in the org.opensourcephysics package
 * or any subpackage (subdirectory) of this package must must also be be released
 * under the GNU GPL license.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA
 * or view the license online at http://www.gnu.org/copyleft/gpl.html
 *
 * Copyright (c) 2007  The Open Source Physics project
 *                     http://www.opensourcephysics.org
 */
